from deal.exchange.backup.base_exchange import *
import ccxt.async_support as ccxt
import asyncio
import time

class BinanceSpotCCXT(BaseExchange):
    """使用CCXT实现币安现货交易"""
    
    def __init__(self, api_key: str = "", api_secret: str = "", testnet: bool = False):
        super().__init__(api_key, api_secret)
        self.name = "BinanceSpot"
        self.testnet = testnet
        
        # 初始化ccxt客户端
        self.client = ccxt.binance({
            'apiKey': api_key,
            'secret': api_secret,
            'enableRateLimit': True,
            'options': {
                'defaultType': 'spot'  # 现货模式
            }
        })
        
        # 设置测试网
        if testnet:
            self.client.set_sandbox_mode(True)
            
        # 缓存数据
        self.tickers = {}
        self.orderbooks = {}
        self.balances = {}
        
    async def connect(self):
        """连接交易所"""
        try:
            await self.client.load_markets()
        except Exception as e:
            raise Exception(f"Failed to connect: {str(e)}")
            
    async def get_ticker(self, symbol: str) -> Ticker:
        """获取最新行情"""
        try:
            ticker = await self.client.fetch_ticker(symbol)
            return Ticker(
                symbol=symbol,
                last_price=float(ticker['last']),
                bid_price=float(ticker['bid']),
                ask_price=float(ticker['ask']),
                volume_24h=float(ticker['baseVolume']),
                timestamp=ticker['timestamp']
            )
        except Exception as e:
            raise Exception(f"Failed to get ticker: {str(e)}")
            
    async def get_orderbook(self, symbol: str, limit: int = 20) -> OrderBook:
        """获取订单簿"""
        try:
            orderbook = await self.client.fetch_order_book(symbol, limit)
            return OrderBook(
                asks=[(float(price), float(qty)) for price, qty in orderbook['asks']],
                bids=[(float(price), float(qty)) for price, qty in orderbook['bids']],
                timestamp=orderbook['timestamp']
            )
        except Exception as e:
            raise Exception(f"Failed to get orderbook: {str(e)}")
            
    async def get_balance(self, asset: str = "") -> Dict[str, Balance]:
        """获取现货账户余额"""
        try:
            # 指定获取现货账户余额
            balance = await self.client.fetch_balance({
                'type': 'spot'  # 指定现货账户
            })
            
            balances = {}
            # 只处理非零余额
            for currency in balance['total'].keys():
                if balance['total'][currency] > 0:  # 只返回有余额的资产
                    if not asset or currency == asset:
                        balances[currency] = Balance(
                            asset=currency,
                            free=float(balance['free'][currency]),
                            locked=float(balance['used'][currency]),
                            total=float(balance['total'][currency]),
                            timestamp=time.time()
                        )
            return balances
        except Exception as e:
            raise Exception(f"Failed to get spot balance: {str(e)}")
            
    def _validate_symbol(self, symbol: str):
        """验证交易对格式"""
        if not symbol or not isinstance(symbol, str):
            raise ValueError("Invalid symbol")
            
    def _validate_amount(self, amount: float):
        """验证数量"""
        if not amount or not isinstance(amount, (int, float)) or amount <= 0:
            raise ValueError("Invalid amount")
            
    def _validate_price(self, price: float):
        """验证价格"""
        if not price or not isinstance(price, (int, float)) or price <= 0:
            raise ValueError("Invalid price")

    async def create_order(self, symbol: str, side: OrderSide, 
                         order_type: OrderType, quantity: float,
                         price: float = None) -> Order:
        """创建订单"""
        try:
            # 验证参数
            self._validate_symbol(symbol)
            self._validate_amount(quantity)
            if order_type == OrderType.LIMIT:
                self._validate_price(price)
                
            # 转换参数
            ccxt_side = 'buy' if side == OrderSide.BUY else 'sell'
            ccxt_type = 'market' if order_type == OrderType.MARKET else 'limit'
            
            # 构建参数
            params = {}
            if order_type == OrderType.LIMIT:
                response = await self.client.create_limit_order(
                    symbol=symbol,
                    side=ccxt_side,
                    amount=quantity,
                    price=price
                )
            else:
                response = await self.client.create_market_order(
                    symbol=symbol,
                    side=ccxt_side,
                    amount=quantity
                )
                
            return Order(
                exchange_id=self.name,
                order_id=str(response['id']),
                symbol=symbol,
                order_type=order_type,
                side=side,
                price=float(response['price']) if 'price' in response else 0,
                amount=float(response['amount']),
                filled=float(response['filled']),
                status=self._convert_status(response['status']),
                timestamp=response['timestamp']
            )
            
        except Exception as e:
            raise Exception(f"Failed to create order: {str(e)}")
            
    async def cancel_order(self, symbol: str, order_id: str) -> bool:
        """取消订单"""
        try:
            await self.client.cancel_order(order_id, symbol)
            return True
        except Exception as e:
            raise Exception(f"Failed to cancel order: {str(e)}")
            
    async def get_order(self, symbol: str, order_id: str) -> Order:
        """获取订单信息"""
        try:
            order = await self.client.fetch_order(order_id, symbol)
            
            return Order(
                exchange_id=self.name,
                order_id=str(order['id']),
                symbol=symbol,
                order_type=OrderType.MARKET if order['type'] == 'market' else OrderType.LIMIT,
                side=OrderSide.BUY if order['side'] == 'buy' else OrderSide.SELL,
                price=float(order['price']),
                amount=float(order['amount']),
                filled=float(order['filled']),
                status=self._convert_status(order['status']),
                timestamp=order['timestamp']
            )
            
        except Exception as e:
            raise Exception(f"Failed to get order: {str(e)}")
            
    def _convert_status(self, status: str) -> OrderStatus:
        """转换订单状态"""
        status_map = {
            'open': OrderStatus.PENDING,
            'closed': OrderStatus.FILLED,
            'canceled': OrderStatus.CANCELED,
            'expired': OrderStatus.EXPIRED,
            'rejected': OrderStatus.REJECTED
        }
        return status_map.get(status, OrderStatus.PENDING)
        
    async def close(self):
        """关闭连接"""
        try:
            await self.client.close()
        except Exception as e:
            self.logger.error(f"Error closing connection: {str(e)}")

    async def create_market_order(self, symbol: str, side: OrderSide, 
                                quantity: float) -> Order:
        """创建市价单"""
        return await self.create_order(
            symbol=symbol,
            side=side,
            order_type=OrderType.MARKET,
            quantity=quantity
        )

    async def create_limit_order(self, symbol: str, side: OrderSide,
                               price: float, quantity: float) -> Order:
        """创建限价单"""
        return await self.create_order(
            symbol=symbol,
            side=side,
            order_type=OrderType.LIMIT,
            quantity=quantity,
            price=price
        )

    async def get_open_orders(self, symbol: str = "") -> List[Order]:
        """获取未完成订单"""
        try:
            orders = await self.client.fetch_open_orders(symbol if symbol else None)
            return [
                Order(
                    exchange_id=self.name,
                    order_id=str(order['id']),
                    symbol=order['symbol'],
                    order_type=OrderType.MARKET if order['type'] == 'market' else OrderType.LIMIT,
                    side=OrderSide.BUY if order['side'] == 'buy' else OrderSide.SELL,
                    price=float(order['price']),
                    amount=float(order['amount']),
                    filled=float(order['filled']),
                    status=self._convert_status(order['status']),
                    timestamp=order['timestamp']
                )
                for order in orders
            ]
        except Exception as e:
            raise Exception(f"Failed to get open orders: {str(e)}")

    async def get_positions(self, symbol: str = "") -> Dict[str, Position]:
        """获取持仓信息 - 现货不支持"""
        return {}

    async def set_leverage(self, symbol: str, leverage: int) -> bool:
        """设置杠杆倍数 - 现货不支持"""
        return False

    async def get_funding_rate(self, symbol: str) -> float:
        """获取资金费率 - 现货不支持"""
        return 0.0

    async def get_funding_time(self, symbol: str) -> int:
        """获取下次资金费时间 - 现货不支持"""
        return 0

async def main():
    key = "3S4j9rBxss0KBivifkgMMEykgWad9GEMl9hdgMhViiwKGNDy5NoLkYHIDg6K3VU5"
    secret = "NzWj2BnVToddcO39tkJp7N1Xz041EYwzgVibMV7czf0ZaHWfuCM8GHnO8pBp03xH"
    
    exchange = BinanceSpotCCXT(
        api_key=key,
        api_secret=secret,
        testnet=False
    )
    
    try:
        await exchange.connect()
        
        symbol = "ACT/USDT"  # 使用正确的符号格式
        
        # 获取交易对信息
        market = await exchange.client.fetch_market(symbol)
        print(f"交易对信息: {market}")
        
        # 获取当前价格
        ticker = await exchange.get_ticker(symbol)
        print(f"ACT当前价格: {ticker.last_price}")
        
        # 计算最小交易金额（通常是10 USDT）
        min_notional = 10  # Binance大多数交易对的最小交易金额是10 USDT
        
        # 计算需要购买的数量
        quantity = min_notional / ticker.last_price
        # 向上取整到合适的精度
        quantity = exchange.client.amount_to_precision(symbol, quantity)
        
        print(f"计划购买数量: {quantity} ACT")
        
        # 获取账户余额
        balances = await exchange.get_balance()
        print("账户余额:", balances)
        
        # 检查USDT余额
        required_usdt = float(quantity) * ticker.last_price
        if 'USDT' not in balances or balances['USDT'].free < required_usdt:
            print(f"USDT余额不足，需要 {required_usdt} USDT")
            return
            
        # 市价买入
        order = await exchange.create_order(
            symbol=symbol,
            side=OrderSide.BUY,
            order_type=OrderType.MARKET,
            quantity=float(quantity)
        )
        print(f"订单ID: {order.order_id}")
        
    except Exception as e:
        print(f"发生错误: {str(e)}")
        print(f"错误类型: {type(e)}")
        import traceback
        print(f"错误堆栈: {traceback.format_exc()}")
        
    finally:
        await exchange.close()

if __name__ == "__main__":
    asyncio.run(main()) 